import Axios from 'axios'
const MD5 = require('js-md5')

class Haier {
    constructor({ baseURL }) {
        Axios.defaults.withCredentials = true
        this.req = Axios.create({
            baseURL: baseURL
        })
        this.req.defaults.withCredentials = true;
    }

    request(method, path, params) {
        params = params || {}
        for (let i = 0; i < arguments.length; i++) {
            var o = arguments[i]
            if (o && o instanceof Object) {
                Object.assign(params, o)
            }
        }
        return new Promise((resolve, reject) => {
            this.req.request(Object.assign({
                method: method,
                url: path
            }, params)).then(res => {
                let { data, headers } = res
                if (!(data || data.status == 2000) && headers['content-type'] !== 'application/json') {
                    reject(res)
                } else {
                    resolve(data)
                }
            }).catch(reject)
        })
    }

    upload(path, data, params) {
        var formData = new FormData()
        var appendFiles = (_files) => {
            _files.forEach((item) => {
                if (data instanceof File || data instanceof Object) {
                    formData.append(`files`, item)
                }
            })
        }
        if (data instanceof Array) {
            appendFiles(data)
        } else if (data instanceof Object) {
            for (const [key, values] of Object.entries(data)) {
                if (values instanceof Array) {
                    appendFiles(values)
                } else {
                    formData.append(key, values)
                }
            }
        }
        return this.request("POST", path, params, {
            headers: {
                'content-type': 'multipart/form-data'
            },
            data: formData
        })
    }

    post(path, data, params) {
        return this.request('POST', path, params, { data: data })
    }

    get(path, query, params) {
        return this.request("GET", path, params, { params: query })
    }

    delete(path, query, params){
        return this.request("DELETE", path, params, {params: query})
    }

    clearValue(o) {
        if (!o || !(o instanceof Object)) return
        Object.keys(o).forEach(key => {
            if (o[key] instanceof Array) {
                o[key] = []
            } else if (o[key] instanceof Object) {
                if (o != o[key]) {
                    this.clearValue(o[key])
                }
            } else {
                o[key] = undefined;
            }
        });
    }
}


const mapping = function (o, mapping, vm) {
    if (!(o instanceof Object)) {
        console.error("mapping object error")
        return
    }
    for (const [k, v] of Object.entries(mapping)) {
        let _value = o[k] ? o[k] : o[v]
        vm.$set(o, k, _value)
        Object.defineProperty(o, k, {
            configurable: true,
            get: () => _value,
            set: (v) => _value = v
        })
    }
}


/* eslint-disable */
const callback = function ({ }, { arg, value, modifiers}, { context }) {
    if (!(arg && context[arg] instanceof Object)) {
        console.error("require configure mapping!")
        return
    }
    var source = value;
    if (modifiers.array || source instanceof Array) {
        source.forEach(item => mapping(item, context[arg], context))
    } else if (source instanceof Object) {
        mapping(source, context[arg], context)
    } else {
        console.error("require configure mapping!")
    }
}


export default {

    install(Vue, options) {
        Array.from(arguments).forEach(o => {
            if (!(o instanceof Object)) return
            if (o.name === "VueRouter" && o.prototype.push) {
                var push = o.prototype.push
                o.prototype.push = function (params) {
                    return push.call(this, params).catch(() => { })
                }
            }
        })
        Vue.prototype.$haier = new Haier({
            baseURL: (options && options.url) || 'http://localhost:8080/api/'
        })
        Vue.prototype.$md5 = MD5
        Vue.prototype.$copy = function (target, source) {
            Object.assign(target, JSON.parse(JSON.stringify(source)))
        }
        Vue.directive('mapping', {
            bind: callback,
            update: callback
        })
    }
}
